/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
 
package com.cburch.logisim.comp;


import java.awt.Graphics;
import java.util.List;

import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Location;

public interface Component {
    // listener methods
	/**
	 * Adds a <code>ComponentListener</code> listener to the class.
	 * @param l a <code>ComponentListener</code> to add to the class
	 */
    public void addComponentListener(ComponentListener l);
    
    /**
     * Removes a <code>componentListener</code> from the class.
     * @param l the <code>componentListener</code> to remove
     */
    public void removeComponentListener(ComponentListener l);

    // basic information methods
    /**
     * Returns the <code>ComponentFactory</code> associated with this class.
     * @return the <code>ComponentFactory</code>
     */
    public ComponentFactory getFactory();
    
    /**
     * Returns the <code>AttributeSet</code> associated with this class.
     * @return the <code>AttributeSet</code>
     */
    public AttributeSet getAttributeSet();

    /**
     * Returns the <code>Attribute</code> value from the <code>Attribute</code> parameter
     * @param attr <code>Attribute</code> to return the value from
     * @return <code>Object</code> value of the Attribute
     */
    public Object getAttributeValue(Attribute attr);
    
    /**
     * Set the <code>Attribute</code> value
     * @param attr <code>Attribute</code> to set the value of
     * @param value <code>Object</code> value
     */
    public void setAttributeValue(Attribute attr, Object value);
    
    // location/extent methods
    
    /**
     * Get the <code>Location</code> associated with this <code>Component</code>.
     * @return a <code>Location</code> object
     */
    public Location getLocation();
    
    /**
     * Get the <code>Bounds</code> associated with this <code>Component</code>.
     * @return a <code>Bounds</code> object
     */
    public Bounds getBounds();
    
    /**
     * Determines the <code>Bounds</code> of the <code>Component</code> within
     * the <code>Graphics</code> context.
     * @param g <code>Graphics</code> where the <code>Component</code> is drawn
     * @return <code>Bounds</code> of the <code>Component</code>
     */
    public Bounds getBounds(Graphics g);
    
    /**
     * Determines if the <code>Location</code> is within the <code>Component</code> <code>Bounds</code>.
     * @param pt <code>Location</code> point
     * @return True if the point is within the <code>Component</code>
     */
    public boolean contains(Location pt);
    
    /**
     * Determines if the <code>Location</code> is within the <code>Component</code> <code>Bounds</code>
     * of the <code>Graphics</code> parameter.
     * @param pt <code>Location</code> point
     * @param g <code>Graphics</code> where the <code>Component</code> is located
     * @return True if the point is within the <code>Graphics</code> and <code>Component</code>
     */
    public boolean contains(Location pt, Graphics g);

    // user interface methods
    
    /**
     * Repaints the <code>ComponentDrawContext</code> destination.
     * @param context <code>ComponentDrawContext</code> to repaint
     */
    public void expose(ComponentDrawContext context);
    
    /**
     * Draws the <code>ComponentDrawContext</code>.
     * @param context <code>ComponentDrawContext</code> to draw
     */
    public void draw(ComponentDrawContext context);
    
    /**
     * Retrieves information about a special-purpose feature for this
     * component. This technique allows future Logisim versions to add
     * new features for components without requiring changes to existing
     * components. It also removes the necessity for the Component API to
     * directly declare methods for each individual feature.
     * In most cases, the <code>key</code> is a <code>Class</code> object
     * corresponding to an interface, and the method should return an
     * implementation of that interface if it supports the feature.
     * 
     * As of this writing, possible values for <code>key</code> include:
     * <code>Pokable.class</code>, <code>CustomHandles.class</code>,
     * <code>WireRepair.class</code>, <code>TextEditable.class</code>,
     * <code>MenuExtender.class</code>, <code>ToolTipMaker.class</code>,
     * <code>ExpressionComputer.class</code>, and <code>Loggable.class</code>.
     * 
     * @param key  an object representing a feature.
     * @return an object representing information about how the component
     *    supports the feature, or <code>null</code> if it does not support
     *    the feature.
     */
    public Object getFeature(Object key);
    
    // propagation methods
    
    /**
     * Returns a <code>List</code> of <code>EndData</code>.
     * @return <code>List</code>
     */
    public List getEnds(); // list of EndDatas
    
    /**
     * Returns the <code>EndData</code> at the index.
     * @param index <code>int</code> location of the <code>EndData</code>
     * @return <code>EndData</code> representing the boundary of the <code>Component</code>
     */
    public EndData getEnd(int index);
    
    /**
     * Determines if the <code>Location</code> is on a boundary point of the <code>Component</code>.
     * @param pt <code>Location</code> to test on the boundary
     * @return True if the <code>Location</code> is within an end point
     */
    public boolean endsAt(Location pt);
    
    /**
     * Propagates the signal with the <code>CircuitState</code>.
     * @param state <code>CircuitState</code> current state
     */
    public void propagate(CircuitState state);    
    
}
